#pragma once
#include <vector>
#include <d3d11.h>
#include "..\..\EdgeMath\Vectors.h"
#include "..\ConstantBuffer.h"
#include "..\ShaderContainer.h"
#include "PointLight.h"
#include "Light.h"
#include "../../Shaders/Defs/ConstantBuffers.hlsli"

#define MAX_LIGHTS 4
#define checkLightTypes(ptr) (dynamic_cast<PointLight*>(ptr) || dynamic_cast<DirectionalLight*>(ptr))

using namespace std;

class ScreenQuad;
class Camera;
class RenderTarget;

class LightingEngine
{
	// the constant buffer to send to video memory that contains lighting information
	ConstantBuffer<VRAM_LIGHTING>* lighting_buffer;

	VRAM_VIEWPROJ viewProj;
	// constant buffer for the view-projection matrix
	ConstantBuffer<VRAM_VIEWPROJ>* viewProj_buffer = nullptr;
	ConstantBuffer<VRAM_VIEWPROJ>* lightingViewProj_buffer = nullptr;
	ConstantBuffer<VRAM_LIGHTING>* sceneLightingBuffer = nullptr;

	// shaders
	ShaderContainer* shader_renderPointLights = nullptr;
	ShaderContainer* shader_renderDirLights = nullptr;

	// render targets
	RenderTarget* diffuseMap = nullptr;
	RenderTarget* normalMap = nullptr;
	RenderTarget* specularMap = nullptr;
	RenderTarget* lightMap = nullptr;
	RenderTarget* depthMap = nullptr;

	//DepthBuffer* depthBuffer = nullptr;

	// quad renderer
	ScreenQuad* screenQuad;

	// collection of lights
	vector<Light*> lights;

	LightingEngine(void);
	~LightingEngine(void);

	VRAM_POINTLIGHT pointLight;
	VRAM_DIRECTIONALLIGHT directionalLight;

	ConstantBuffer<VRAM_DIRECTIONALLIGHT>* directionalLightBuffer = nullptr;
	ConstantBuffer<VRAM_POINTLIGHT>* pointLightBuffer = nullptr;
public:
	VRAM_WORLD world;
	VRAM_LIGHTING lighting;
	// constant buffer that holds the world matrix
	ConstantBuffer<VRAM_WORLD>* world_buffer = nullptr;	

	void RenderLights(void);
	void BeginDrawScene(Camera* camera);
	void EndDrawScene(void);

	void DrawDiffered(void);

	template<typename T>
	void AddLight(T* light);

	// retrieve a light from the engine based on index
	PointLight* getLightIndex(int index);


	// set the ambiant color of the lighting engine
	void setAmbiant(Vector3& value) { lighting.gAmbiantColor.setXyz(value); }

	static LightingEngine* GetInstance(void);
};

template<typename T>
void LightingEngine::AddLight(T* light)
{
	assert(checkLightTypes(light) && "Invalid type of light");

	lights.push_back(light);
}